package com_.dxy_test_.utils_;

import cn.hutool.core.date.DateUtil;
import jodd.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;

/**
 * All rights Reserved, Designed By https://www.pcitech.com
 *
 * @version v1.0
 * @Title: DateTimeUtils
 * @Description: 日期工具类
 * @author: lyp林永坡
 * @date: 2022年2月16日 下午5:09:03
 * @Copyright: 2022 https://www.pcitech.com Inc. All rights reserved.
 * @warning: 本内容仅限于佳都新太科技股份有限公司内部传阅，禁止外泄以及用于其他的商业目
 */
public class DateTimeUtils {

    public static final String DEFAULTFORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String TSFORMAT = "yyyyMMddHHmmss";
    public static final String EASYFORMAT = "yyyy年MM月dd日 HH:mm";
    public static final String DATEFORMAT = "yyyy-MM-dd";
    public static final String MONTHFORMAT = "yyyy-MM";
    public static final String YEARFORMAT = "yyyy";


    public static String formatDate(Date d, String format) {
        Locale locale = Locale.CHINA;
        SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
        return sdf.format(d);
    }

    public static String getCurrentDate() {
        return formatDateTime(LocalDateTime.now());
    }

    public static String getCurrentDate(String format) {
        return formatDate(new Date(), format);
    }

    public static Date getDate(String str, String format) {
        Locale locale = Locale.CHINA;
        if (StringUtils.length(str) < StringUtils.length(format)) {
            format = StringUtils.substring(format, 0, StringUtils.length(str));
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
        try {
            return sdf.parse(str);
        } catch (ParseException e) {
            return new Date();
        }
    }

    public static Date getDate(String str) {
        return getDate(str, DATEFORMAT);
    }

    public static String formatDate(String str, String informat, String outFormat) {
        return formatDate(getDate(str, informat), outFormat);
    }

    public static String getShortDate(String str) {
        if (StringUtils.isBlank(str)) {
            return "";
        } else {
            return StringUtils.substring(str, 0, 10);
        }
    }

    /**
     * @return 返回今天“yyyy-MM-dd HH:mm:ss”格式的时间字符串
     * @author ChenJq
     */
    public static String getTodayBySimpleFormat() {
        return getTodayByFormat(DEFAULTFORMAT);
    }

    /**
     * @param timeFormat 日期格式
     * @return 返回今天指定格式的时间字符串
     */
    public static String getTodayByFormat(String timeFormat) {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(timeFormat));
    }

    /**
     * 把一个日期格式的字符串转为另外一种日期格式字符串
     *
     * @param srcTime       源日期字符串
     * @param srcFormat     源日期格式
     * @param dstTimeFormat 目标日期格式
     * @return 目标日期字符串
     */
    public static String transTimeFormat(String srcTime, String srcFormat, String dstTimeFormat) {
        LocalDateTime srcDataTime = LocalDateTime.parse(srcTime, DateTimeFormatter.ofPattern(srcFormat));
        return srcDataTime.format(DateTimeFormatter.ofPattern(dstTimeFormat));
    }

    /**
     * 获取指定日期时间的最后一秒
     *
     * @param srcTime 日期时间 格式 yyyy-MM-dd或者 yyyy-MM-dd HH:mm:ss
     * @return 日期时间的最后一秒, 格式yyyy-MM-dd HH:mm:ss 例如 2018-02-28 23:59:59
     */
    public static String getDateEndTime(String srcTime) {
        if (StringUtil.isEmpty(srcTime)) {
            return null;
        }
        int dateTimeLength = 10;
        if (srcTime.length() > dateTimeLength) {
            srcTime = srcTime.substring(0, 10);
        }

        return srcTime + " 23:59:59";
    }

    public static String getDateEndTime(LocalDate localDate) {
        if (Objects.isNull(localDate)) {
            return null;
        }
        return formatDate(localDate) + " 23:59:59";
    }

    /**
     * 获取指定日期时间的最开始一秒
     *
     * @param srcTime 日期时间 格式 yyyy-MM-dd或者 yyyy-MM-dd HH:mm:ss
     * @return 日期时间的最开始一秒, 格式yyyy-MM-dd HH:mm:ss 例如 2018-02-28 00:00:00
     */
    public static String getDateBeginTime(String srcTime) {
        if (StringUtil.isEmpty(srcTime)) {
            return null;
        }
        int dateTimeLength = 10;
        if (srcTime.length() > dateTimeLength) {
            srcTime = srcTime.substring(0, 10);
        }

        return srcTime + " 00:00:00";
    }

    public static String getDateBeginTime(LocalDate localDate) {
        if (Objects.isNull(localDate)) {
            return null;
        }
        return formatDate(localDate) + " 00:00:00";
    }

    /**
     * 获取当前时间距离到第二天0点0分的间隔
     *
     * @return 时间间隔，单位秒
     */
    public static long getInterval2NextData() {
        // 时间加减的demo
        LocalDateTime currentTime = LocalDateTime.now();

        // 第二天零点时间
        LocalDateTime nextDateTime = currentTime.plusDays(1).minusHours(currentTime.getHour())
                .minusMinutes(currentTime.getMinute()).minusSeconds(currentTime.getSecond());

        Duration duration = Duration.between(currentTime, nextDateTime);
        // 加上60秒，延迟一分钟
        return duration.toMinutes() * 60 + 60;

    }

    /**
     * 获取时间字符串的毫秒数
     *
     * @param timeStr
     * @return 毫秒
     * @throws ParseException
     */
    public static long getMsecOfTimeStr(String timeStr) throws ParseException {
        DateFormat format = new SimpleDateFormat(DEFAULTFORMAT);
        return format.parse(timeStr).getTime();
    }

    /**
     * 时间格式化
     *
     * @param datetime 要格式的时间，默认数据是yyyy-MM-dd HH:mm:ss格式
     * @param format   格式
     * @return
     */
    public static String format(String datetime, String format) {
        return format(datetime, DEFAULTFORMAT, format);
    }

    /**
     * @param datetime     时间
     * @param sourceFormat 时间源格式
     * @param targetFormat 目标格式
     * @return
     */
    public static String format(String datetime, String sourceFormat, String targetFormat) {
        try {
            SimpleDateFormat sourceFmt = new SimpleDateFormat(sourceFormat);
            SimpleDateFormat targetFmt = new SimpleDateFormat(targetFormat);
            return targetFmt.format(sourceFmt.parse(datetime));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return "";
    }

    public static String format(Date date, String format) {
        try {
            SimpleDateFormat targetFmt = new SimpleDateFormat(format);
            return targetFmt.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "";
    }

    public static String getDateTime(String format, int yearOffset, int monthOffset, int dayOffset) {
        Calendar now = Calendar.getInstance();
        if (yearOffset != 0) {
            now.add(Calendar.YEAR, yearOffset);
        }
        if (monthOffset != 0) {
            now.add(Calendar.MONTH, monthOffset);
        }
        if (dayOffset != 0) {
            now.add(Calendar.DAY_OF_MONTH, dayOffset);
        }

        try {
            SimpleDateFormat targetFmt = new SimpleDateFormat(format);
            return targetFmt.format(now.getTime());
        } catch (Exception e) {
        }

        return "";
    }

    public static String getDateTime(Date date, String format, int yearOffset, int monthOffset, int dayOffset) {
        Calendar now = Calendar.getInstance();
        if (date != null) {
            now.setTime(date);
        }
        if (yearOffset != 0) {
            now.add(Calendar.YEAR, yearOffset);
        }
        if (monthOffset != 0) {
            now.add(Calendar.MONTH, monthOffset);
        }
        if (dayOffset != 0) {
            now.add(Calendar.DAY_OF_MONTH, dayOffset);
        }

        try {
            SimpleDateFormat targetFmt = new SimpleDateFormat(format);
            return targetFmt.format(now.getTime());
        } catch (Exception e) {
        }

        return "";
    }

    /**
     * 获取该时间所在月份的每个相同星期的日期
     *
     * @param dateStr   日期字符串
     * @param formatter 格式化
     * @param dayOfWeek 星期
     * @return
     */
    public static List<Object> getWeeksOfMonth(String dateStr, String formatter, DayOfWeek dayOfWeek) {
        LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(formatter));
        LocalDate mondayOfMonth = date.withDayOfMonth(1);

        while (mondayOfMonth.getDayOfWeek() != dayOfWeek) {
            mondayOfMonth = mondayOfMonth.plusDays(1);
        }

        List<Object> days = new ArrayList<>();
        int monthValue = date.getMonthValue();
        while (mondayOfMonth.getMonthValue() == monthValue) {
            String dayOfMonday = mondayOfMonth.format(DateTimeFormatter.ISO_LOCAL_DATE);
            days.add(dayOfMonday);
            mondayOfMonth = mondayOfMonth.plusDays(7);
        }

        return days;
    }

    /**
     * 比较两个日期字符串的大小，dateStr1-dateStr2，返回两者的时间差（单位：毫秒）
     *
     * @param dateStr1  第一个日期字符串
     * @param dateStr2  第二个日期字符串
     * @param formatter 日期字符串的转化格式
     * @return 返回值 >0，表示dateStr1较大；返回值<0，表示dateStr1较小；返回值=0，表示两者相等
     */
    public static Long compareDataTimeByStr(String dateStr1, String dateStr2, String formatter) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(formatter);
            // 将字符串形式的时间转化为Date类型的时间
            Date a = sdf.parse(dateStr1);
            Date b = sdf.parse(dateStr2);
            return a.getTime() - b.getTime();
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 格式化日期时间
     */
    public static String formatDateTime(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return "";
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern(DEFAULTFORMAT);
        return df.format(localDateTime);
    }

    /**
     * 格式化日期时间
     */
    public static String formatDate(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return "";
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern(DATEFORMAT);
        return df.format(localDateTime);
    }

    /**
     * 格式化日期
     */
    public static String formatDate(LocalDate localDate) {
        if (localDate == null) {
            return "";
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern(DATEFORMAT);
        return df.format(localDate);
    }


    /**
     * 日期时间转字符串，格式：yyyy-MM-dd HH:mm:ss
     *
     * @param dateTimeStr 日期时间
     * @return
     */
    public static LocalDateTime parseLocalDateTime(String dateTimeStr, String pattern) {
        return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 用来判断是否是未来
     *
     * @param m1   校验月份
     * @param year 校验年
     * @return
     */
    public static boolean checkAfter(int m1, int year) {
        //当前月份+1  因为从0开始所以+1
        int m2 = DateUtil.month(new Date()) + 1;
        if (DateUtil.thisYear() == year && m1 > m2) {
            return true;
        } else if (year > DateUtil.thisYear()) {
            return true;
        }
        return false;
    }

    /**
     * 获取时间区间内的每一天
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static Set<String> getBetweenDate(LocalDate startDate, LocalDate endDate) {
        Set<String> set = new HashSet<>();
        long distance = ChronoUnit.DAYS.between(startDate, endDate);
        Stream.iterate(startDate, date -> date.plusDays(1))
                .limit(distance + 1)
                .forEach(day -> set.add(day.format(DateTimeFormatter.ofPattern(DATEFORMAT))));
        return set;
    }

    /**
     * 获取区间的每一天
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<LocalDate> getIntervalPerDay(@NonNull LocalDate startDate, @NonNull LocalDate endDate) {
        List<LocalDate> list = new ArrayList<>();
        LocalDate perDay = startDate;
        while (!perDay.isAfter(endDate)) {
            list.add(perDay);
            perDay = perDay.plusDays(1);
        }
        return list;
    }

    /**
     * 判断是否日期区间内
     *
     * @param startDate 为空表示无限过去
     * @param endDate   为空表示无限未来
     * @param localDate 当前日期
     * @return
     */
    public static boolean isInInterval(LocalDate startDate, LocalDate endDate, LocalDate localDate) {
        return (startDate == null || !startDate.isAfter(localDate)) && (endDate == null || !endDate.isBefore(localDate));
    }


    /**
     * 获取一周中的第几天（星期一是第一天）
     *
     * @param localDate
     * @return
     */
    public static int getDayOfWeekMondayFirstDay(LocalDate localDate) {
        return localDate.getDayOfWeek().getValue();
    }

    /**
     * 获取一周中的第几天（星期日为第一天）
     *
     * @param localDate
     * @return
     */
    public static int getDayOfWeekSundayFirstDay(LocalDate localDate) {
        if (localDate.getDayOfWeek() == DayOfWeek.SUNDAY) {
            return 1;
        }
        return localDate.getDayOfWeek().getValue() + 1;
    }

    /**
     * 获取最近的周末的日期
     *
     * @return
     */
    public static LocalDate getLastSunday() {
        LocalDate now = LocalDate.now();
        if (DayOfWeek.SUNDAY == now.getDayOfWeek()) {
            return now;
        } else {
            return now.minusDays(now.getDayOfWeek().getValue());
        }
    }


    /**
     * 获取本日开始时间
     * @return
     */
    public static String getDayStart() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern(DATEFORMAT))
                + " 00:00:00";
    }

    /**
     * 获取本周开始时间（周一为第一天）
     * @return
     */
    public static String getWeekStart() {
        // 获取本周的开始日期（星期一为第一天）
        LocalDate firstDayOfCurrentWeek = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        return firstDayOfCurrentWeek.format(DateTimeFormatter.ofPattern(DATEFORMAT))
                + " 00:00:00";
    }

    /**
     * 获取本月开始时间
     * @return
     */
    public static String getMonthStart() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern(MONTHFORMAT))
                + "-01 00:00:00";
    }

    /**
     * 获取本年开始时间
     * @return
     */
    public static String getYearStart() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern(YEARFORMAT))
                + "-01-01 00:00:00";
    }


}
